package procedure;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 流程计算产能
 *
 * @author sk.z
 */
public class Calculate {

    private static final String DELIMITER = "+";

    //串行合并计算
    public static Node mergeSerial(List<Node> nodeList) {
        for (int i = 0; i < nodeList.size(); i++) {
            Node curNode = nodeList.get(i);

            //产能计算
            int tempProduct = curNode.getProduce();
            int cursor = i + 1;
            while (cursor < nodeList.size()) {
                Node next = nodeList.get(cursor);
                cursor++;
                tempProduct = tempProduct * next.getQualifiedPercent() / 10000;
            }
            curNode.setTempProduce(tempProduct);
        }

        Node minNode = minTempProduce(nodeList);
        int oee = mergeOEE(nodeList);
        int newId = nodeList.stream().mapToInt(Node::getId).sum();
        String newName = nodeList.stream().map(Node::getName).collect(Collectors.joining(DELIMITER));
        Node result = new Node(newId, newName, minNode.getTempProduce(), oee);

        //2022/03/23 - 工序id合并
        WorkId workId = new WorkId();
        nodeList.forEach(e -> workId.merge(e.getWorkId()));
        result.setWorkId(workId);

        //写入瓶颈
        if (minNode.getBottleneck().size() > 0) {
            result.getBottleneck().addAll(minNode.getBottleneck());
        } else {
            result.getBottleneck().add(minNode);
        }
        return result;
    }

    //并行合并计算
    public static Node mergeParallel(List<Node> nodeList) {
        if (haveSameLeftSame(nodeList)) {
            return mergeParallelSame(nodeList);
        } else {
            return mergeParallelDiff(nodeList);
        }
    }

    //并行合并计算 同内容
    private static Node mergeParallelSame(List<Node> nodeList) {
        int produce = nodeList.stream().mapToInt(Node::getProduce).sum();
        int denominator = 0;
        for (Node n : nodeList) {
            denominator = denominator + (n.getProduce() * 10000 / n.getQualifiedPercent());
        }
        int qualify = produce * 10000 / denominator;

        int newId = nodeList.stream().mapToInt(Node::getId).sum();
        String newName = nodeList.stream().map(Node::getName).collect(Collectors.joining(DELIMITER));
        Node result = new Node(newId, newName, produce, qualify);

        //2022/03/23 - 工序id合并
        WorkId workId = new WorkId();
        nodeList.forEach(e -> workId.merge(e.getWorkId()));
        result.setWorkId(workId);

        //写入瓶颈
        for (Node n : nodeList) {
            if (n.getBottleneck().size() > 0) {
                result.getBottleneck().addAll(n.getBottleneck());
            } else {
                result.getBottleneck().add(n);
            }
        }
        return result;
    }

    //并行合并计算 不同内容
    private static Node mergeParallelDiff(List<Node> nodeList) {
        Node minNode = minProduce(nodeList);
        int minQualify = nodeList.stream().mapToInt(Node::getQualifiedPercent).min().orElse(0);

        int newId = nodeList.stream().mapToInt(Node::getId).sum();
        String newName = nodeList.stream().map(Node::getName).collect(Collectors.joining(DELIMITER));
        Node result = new Node(newId, newName, minNode.getProduce(), minQualify);

        //2022/03/23 - 工序id合并
        WorkId workId = new WorkId();
        nodeList.forEach(e -> workId.merge(e.getWorkId()));
        result.setWorkId(workId);

        //写入瓶颈
        if (minNode.getBottleneck().size() > 0) {
            result.getBottleneck().addAll(minNode.getBottleneck());
        } else {
            result.getBottleneck().add(minNode);
        }
        return result;
    }

    //2022/03/23 - 工序id合并
    private static boolean haveSameLeftSame(List<Node> nodeList) {
        boolean haveSame = false;
        Map<WorkId, AtomicInteger> map = new HashMap<>();
        for (Node n : nodeList) {
            WorkId wId = n.getWorkId();
            if (Objects.nonNull(wId) && wId.isNotEmpty()) {
                if (map.containsKey(n.getWorkId())) {
                    map.get(wId).incrementAndGet();
                } else {
                    map.put(wId, new AtomicInteger(1));
                }
            }
        }

        WorkId sameWorkIdId = null;
        for (Map.Entry<WorkId, AtomicInteger> next : map.entrySet()) {
            if (next.getValue().get() > 1) {
                sameWorkIdId = next.getKey();
                haveSame = true;
                break;
            }
        }

        //如果有同内容节点,列表中删除其它点,最终只保留相同点.
        if (haveSame) {
            Iterator<Node> iterator = nodeList.iterator();
            while (iterator.hasNext()) {
                WorkId wId = iterator.next().getWorkId();
                if (Objects.isNull(wId) || !wId.equals(sameWorkIdId)) {
                    iterator.remove();
                }
            }
            System.out.println("存在同工序:" + sameWorkIdId.toString());
        }

        return haveSame;
    }

    private static Node minTempProduce(List<Node> nodeList) {
        Node minNode = null;
        Iterator<Node> iterator = nodeList.iterator();
        while (iterator.hasNext()) {
            Node next = iterator.next();
            if (Objects.isNull(minNode)) {
                minNode = next;
            } else if (minNode.getTempProduce() > next.getTempProduce()) {
                minNode = next;
            }
        }
        return minNode;
    }

    private static Node minProduce(List<Node> nodeList) {
        Node minNode = null;
        for (Node next : nodeList) {
            if (Objects.isNull(minNode)) {
                minNode = next;
            } else if (minNode.getProduce() > next.getProduce()) {
                minNode = next;
            }
        }
        return minNode;
    }

    private static int mergeOEE(List<Node> nodeList) {
        int oee = 10000;
        for (Node n : nodeList) {
            oee = oee * n.getQualifiedPercent() / 10000;
        }
        return oee;
    }
}
